#include "stdafx.h"
#include "Shader.h"
#include "UboMaterial.h"
#include "common.h"

Shaders *Shaders::s_shader = 0;
GLuint Shader::s_currProgramName = 0;

Shader::Shader()
{
	m_program = 0;
	m_uboBoneTransformMat = 0;
	//m_uniformsPtr = 0;
	//m_uniformCount = 0;
}

Shader::~Shader()
{
	if (m_program) glDeleteProgram(m_program);
}

bool Shader::Load(ShaderInfo *si)
{
	m_program = LoadShaders(si);
	_ASSERT(m_program);
	m_locMVP = glGetUniformLocation(m_program, "MVP");
	return m_program;
}

bool Shader::Load(const char *vsFile, const char *fsFile)
{
	ShaderInfo si[] = {
		{ GL_VERTEX_SHADER, vsFile },
		{ GL_FRAGMENT_SHADER, fsFile },
		{ GL_NONE, NULL }
	};
	return Load(si);
}

bool Shader::Load(const char *vsFile, const char *fsFile, const char *gsFile)
{
	ShaderInfo si[] = {
		{ GL_VERTEX_SHADER, vsFile },
		{ GL_FRAGMENT_SHADER, fsFile },
		{ GL_GEOMETRY_SHADER, gsFile },
		{ GL_NONE, NULL }
	};
	return Load(si);
}

bool Shader::UseProgram()
{
	if (s_currProgramName == m_program) return false;
	glUseProgram(m_program);
	s_currProgramName = m_program;
	return true;
}

void Shader::UseProgram0()
{
	glUseProgram(0);
	s_currProgramName = 0;
}

bool Shader::GetUniformsLocation(char **names, int nameCount)
{
	int loc;
	bool result = true;;
	for (int i = 0; i < nameCount; i++)
	{
		loc = glGetUniformLocation(m_program, names[i]);
		if (loc == -1) result = false;
		m_uniformsLocation[names[i]] = loc;
	}
	return result;
}

int Shader::GetUniLoc(char *uniformName)
{
	return m_uniformsLocation[uniformName];
}

bool Shader::SetUbo(char *name, UniformBufferObject *ubo)
{
	int loc = glGetUniformBlockIndex(m_program, name);
	if (loc != -1)
	{
		int ubp = ubo->GetBindPoint();
		glUniformBlockBinding(m_program, loc, ubp);
		m_ubos[name] = ubo;
		return true;
	}
	return false;
}

UniformBufferObject *Shader::GetUbo(char *name)
{
	return m_ubos[name];
}

void Shader::SetBoneTransformMatUbo(char *name, UniformBufferObject *ubo)
{
	int loc = glGetUniformBlockIndex(m_program, name);
	GLuint uniformBlockBinding = ubo->GetBindPoint();
	glUniformBlockBinding(m_program, loc, uniformBlockBinding);
	m_uboBoneTransformMat = ubo;
}

void Shader::SetMvp(float *mvp)
{
	//UseProgram();
	//glUseProgram(m_program);
	glUniformMatrix4fv(m_locMVP, 1, false, mvp);
}

Shaders *Shaders::GetInstance()
{
	if (!s_shader)
	{
		s_shader = new Shaders;
		s_shader->Init();
	}
	return s_shader;
}

void Shaders::Init()
{
	bool fok;
	glGenVertexArrays(1, &m_vaoNoVert);
	glBindVertexArray(m_vaoNoVert);
	glBindVertexArray(0);

	m_sTexRender.Load(getResPath("shader/texRender.vs.glsl").c_str(), getResPath("shader/texRender.fs.glsl").c_str());
	m_sBoneModel.Load(getResPath("shader/boneModel.vs.glsl").c_str(), getResPath("shader/boneModel.fs.glsl").c_str());
	m_sBallOfFire.Load(getResPath("shader/1.vs.glsl").c_str(), getResPath("shader/ballOfFire.fs.glsl").c_str());
	m_sTerrain.Load(getResPath("shader/terrain.vs.glsl").c_str(), getResPath("shader/terrain.fs.glsl").c_str(), getResPath("shader/terrain.gs.glsl").c_str());
	m_sBoundBox.Load(getResPath("shader/boundBox.vs.glsl").c_str(), getResPath("shader/boundBox.fs.glsl").c_str(), getResPath("shader/boundBox.gs.glsl").c_str());

	m_uBoneTransformMatrix.Init(sizeof(glm::mat4) * max_boneTransformMatrix, 0, bindPoint_boneTransformMatrix);
	m_uboDrawInst.Init(sizeof(DrawInstParams) * max_uboDrawInst, 0, bindPoint_drawInst);
	//m_uLight.Init(sizeof(LightParams) * max_light, 0, bindPoint_light);
	m_uboMaterial.Init("ubLight", m_sBoneModel.m_program, bindPoint_light);
	m_uboMaterial.UseLight(-1, true);

	m_sTerrain.SetUbo("ubMain", &m_uboDrawInst);
	fok = m_sBoundBox.SetUbo("ubDrawParam", &m_uboDrawInst); _ASSERT(fok);
	fok = m_sBoneModel.SetUbo("uBoneTransformMatrix", &m_uBoneTransformMatrix);
	fok = m_sBoneModel.SetUbo("ubLight", &m_uboMaterial);
	fok = m_sBoneModel.SetUbo("ubDrawInstParams", &m_uboDrawInst);

	m_fboColorPick.Init();

	m_texMgr.SetLoadDir("./Data/Player/");
	m_texMgr.GetTexture("hide.OZJ");
	m_texMgr.GetTexture("upper_02_m.OZJ");
	m_texMgr.GetTexture("upper_02b_m.OZT");
	m_texMgr.GetTexture("head_02.OZJ");
	m_texMgr.GetTexture("boots_07.OZJ");
	m_texMgr.GetTexture("gloves_07.OZJ");
	m_texMgr.GetTexture("head_07.OZJ");
	m_texMgr.GetTexture("guard_hair.OZT");

	m_texMgr.SetLoadDir("./Data/Item/");
	m_texMgr.GetTexture("hound_sword1.OZJ");
}

